﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Management;
using System.Net;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
using System.Threading;
using AskPingForm.Properties;
using System.Collections.Specialized;

namespace AskPingForm
{
    public partial class AskPingForm : Form
    {
        #region Members
        static public bool bProcess = false;
        Settings settings = Settings.Default;
        static public StringBuilder strB = new StringBuilder();
        Color TextColorDefault = Color.MidnightBlue;
        string MachineName = "";
        string HostName = "";
        IPHostEntry ipHost;
        string HostDNSName = "";
        //static string userStr = Net.UserName;
        string userStr = "";
        string UserDomainName = "";
        static List<string> pinglist = new List<string>();
        List<ManagementObject> adaptersList = new List<ManagementObject>();
        Thread t = new Thread(ThePing);
        static public int iPingCount = 0;
        #endregion

        #region Tree Nodes
        TreeNode nodeInf;
        #endregion end Tree Nodes

        #region Form Methods
        public AskPingForm()
        {
            InitializeComponent();
            if (IsOffline())
            {
                MessageBox.Show("No internet connection detected.");
                return;
            }
            Init();
        }
        private void Init()
        {
            nodeInf = oLog.Nodes.Add("System Info");
            MachineName = System.Environment.MachineName;
            AddToLogInf("Machine Name = " + MachineName, TextColorDefault);
            HostName = Dns.GetHostName();
            AddToLogInf("Host Name = " + HostName, TextColorDefault);
            ipHost = Dns.Resolve(HostName);
            HostDNSName = ipHost.HostName;
            AddToLogInf("Host DNS Name = " + HostDNSName, TextColorDefault);
            UserDomainName = System.Environment.UserDomainName;
            AddToLogInf("Domain = " + UserDomainName, TextColorDefault);
            userStr = System.Environment.UserName;
            AddToLogInf("User = " + userStr, TextColorDefault);
            AddToLogInf("Platform - " + System.Environment.OSVersion.Platform
                , Color.Olive);
            AddToLogInf("SP - " + System.Environment.OSVersion.ServicePack
                , Color.OliveDrab);
            AddToLogInf("OSVersion - " + System.Environment.OSVersion.Version
                , Color.DarkSeaGreen);

            PrintIPAddress(ipHost);
            PrintProxy();
            PrintAdapters();
            strB.Append("============ Ping ================");
            txtLog.Text = strB.ToString();
            foreach (string s in settings.AddrList)
            {
                pinglist.Add(s);
            }
            txtLog.Text = strB.ToString();
            bProcess = true;
            timer.Interval = 1000;
            timer.Start();
            t.Start();
        }
        private void btnTest_Click(object sender, EventArgs e)
        {
            if (bProcess)
            {
                return;
                // the previous process was not completed
                //ManagementObject mo = adaptersList[oAdapter.SelectedIndex];
                //foreach (string s in mo["DefaultIPGateway"] as string[])
                //    pinglist.Add(s);
            }
            else
            {
                ManagementObject mo = adaptersList[oAdapter.SelectedIndex];
                if (mo["DefaultIPGateway"] != null)
                {
                    pinglist.Clear();
                    foreach (string s in mo["DefaultIPGateway"] as string[])
                        pinglist.Add(s);
                    bProcess = true;
                    timer.Interval = 1000;
                    timer.Start();
                    t = new Thread(ThePing);
                    t.Start();
                }
                else
                {
                    strB.AppendLine("");
                    strB.Append("Default Gateway not found - cancel ping");
                    txtLog.Text = strB.ToString();
                }
            }
        }
        private void oAdapter_SelectedIndexChanged(object sender, EventArgs e)
        {
            btnTest.Enabled = true;
        }
        private TreeNode AddToLogInf(string str, Color color)
        {
            strB.AppendLine(str);
            // Tree
            TreeNode node = nodeInf.Nodes.Add(str);
            node.ForeColor = color;
            return node;
        }
        #endregion end Form Methods

        #region Net Methods
        private bool IsOffline()
        {
            ConnectionState state = 0;
            InternetGetConnectedState(ref state, 0);
            if (((int)ConnectionState.INTERNET_CONNECTION_OFFLINE & (int)state) != 0)
            {
                return true;
            }

            return false;
        }
        void PrintIPAddress(IPHostEntry ipHost)
        {
            string ipAddressStr = "";
            List<string> ipAddress = new List<string>();
            int i = -1;
            foreach (IPAddress ipaddr in ipHost.AddressList)
            {
                ipAddress.Add(ipaddr.ToString());
                i++; if (i > 0) ipAddressStr += " ; ";
                ipAddressStr += ipaddr.ToString();
            }
            AddToLogInf("IP address - " + ipAddressStr, TextColorDefault);
        }
        void PrintProxy()
        {
            IWebProxy proxy = GlobalProxySelection.Select;
            if (proxy != null)
            {
                AddToLogInf("Proxy - " + ((System.Net.WebProxy)(proxy)).Address
                    , TextColorDefault);
            }
        }
        void PrintAdapters()
        {
            ManagementObjectSearcher query = new
                ManagementObjectSearcher(
                    "SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = 'TRUE'");
            ManagementObjectCollection queryCollection = query.Get();
            foreach (ManagementObject mo in queryCollection)
            {
                int i = 0;
                adaptersList.Add(mo);
                strB.AppendLine("========== Adapter ===============");
                string adapterName = "";
                if(mo["Description"]!=null)
                    adapterName = (string)mo["Description"];
                int index = oAdapter.Items.Add(adapterName);
                TreeNode nodeMo = oLog.Nodes.Add(adapterName);
                strB.AppendLine("Adapter : " + adapterName);

                string strMac = "";
                if (mo["MACAddress"] != null)
                    strMac = (string)mo["MACAddress"];
                TreeNode nodeMAC = nodeMo.Nodes.Add("MAC : " + strMac);
                nodeMAC.ForeColor = TextColorDefault;
                strB.AppendLine("MAC : " + strMac);

                if (mo["IPAddress"] != null)
                {
                    strB.AppendLine("IP addresses : ");
                    i = 0;
                    foreach (string IPAddress in mo["IPAddress"] as string[])
                    {
                        i++;
                        TreeNode nodeAddresses =
                            nodeMo.Nodes.Add("IP Addresses : " + IPAddress);
                        nodeAddresses.ForeColor = TextColorDefault;
                        if (i > 1) strB.Append(" ; ");
                        strB.Append(IPAddress);
                    }
                }
                if (mo["IPSubnet"] != null)
                {
                    strB.AppendLine("");
                    strB.AppendLine("IP Subnet : ");
                    i = 0;
                    foreach (string IPSubnet in mo["IPSubnet"] as string[])
                    {
                        i++;
                        TreeNode nodeIPSubnet =
                            nodeMo.Nodes.Add("IP Subnet : " + IPSubnet);
                        nodeIPSubnet.ForeColor = TextColorDefault;
                        if (i > 1) strB.Append(" ; ");
                        strB.Append(IPSubnet);
                    }
                }
                if (mo["DefaultIPGateway"] != null)
                {
                    i = 0;
                    strB.AppendLine("");
                    strB.AppendLine("Default IP Gateway : ");
                    foreach (string DefaultIPGateway in mo["DefaultIPGateway"] as string[])
                    {
                        i++;
                        TreeNode nodeDefaultIPGateway =
                            nodeMo.Nodes.Add("Default IP Gateway : " + DefaultIPGateway);
                        nodeDefaultIPGateway.ForeColor = TextColorDefault;
                        if (i > 1) strB.Append(" ; ");
                        strB.Append(DefaultIPGateway);
                        pinglist.Add(DefaultIPGateway);
                    }
                }
                if (mo["DNSServerSearchOrder"] != null)
                {
                    i = 0;
                    strB.AppendLine("");
                    strB.AppendLine("DNS : ");
                    foreach (string DNSServerSearchOrder in mo["DNSServerSearchOrder"] as string[])
                    {
                        i++;
                        TreeNode nodeDNSServerSearchOrder =
                            nodeMo.Nodes.Add("DNS : " + DNSServerSearchOrder);
                        nodeDNSServerSearchOrder.ForeColor = TextColorDefault;
                        if (i > 1) strB.Append(" ; ");
                        strB.Append(DNSServerSearchOrder);
                        pinglist.Add(DNSServerSearchOrder);
                    }
                }
                strB.AppendLine("");
            }
        }
        static void ThePing()
        {
            foreach (string s in pinglist)
            {
                Ping(s, 3);
            }
            bProcess = false;
        }
        private void timer_Tick(object sender, EventArgs e)
        {
            string alltext = strB.ToString();
            int oldlen = txtLog.Text.Length;
            int newlen = alltext.Length;
            if (newlen > oldlen)
            {
                txtLog.Text += alltext.Substring(oldlen);
            }
            if (bProcess == false)
                timer.Stop();
        }
        static void Ping(string host, int count)
        {
            int received = 0;
            bool bError = false;
            string LastErrorStr = "";
            strB.AppendLine("");
            iPingCount++;
            strB.Append(iPingCount.ToString() + ". ping : " + host.PadRight(18) + " : ");
            for (int i = 0; i < count; i++)
            {
                strB.Append(".");
                IPAddress[] ip;
                try
                {
                    ip = Dns.GetHostAddresses(host);
                }
                catch (System.Net.Sockets.SocketException ex)
                {
                    bError = true;
                    LastErrorStr = ex.Message;
                    break;
                }
                PingOptions options = new PingOptions(128, true);
                Ping ping = new Ping();
                byte[] data = new byte[32];
                List<long> responseTimes = new List<long>();
                PingReply reply = ping.Send(ip[0], 1000, data, options);
                if (reply != null)
                {
                    switch (reply.Status)
                    {
                        case IPStatus.Success:
                            //Console.WriteLine("Reply from {0}: bytes={1} time={2}ms TTL={3}",
                            //    reply.Address, reply.Buffer.Length
                            //    , reply.RoundtripTime, reply.Options.Ttl);
                            received++;
                            //responseTimes.Add(reply.RoundtripTime);
                            break;
                        case IPStatus.TimedOut:
                            LastErrorStr = "Request timed out.";
                            continue;
                        default:
                            bError = true;
                            LastErrorStr =
                                String.Format(
                                    "Ping failed {0}", reply.Status.ToString());
                            break;
                    }
                }
                else
                {
                    bError = true;
                    LastErrorStr = "Ping failed for an unknown reason";
                }
            }
            if (bError)
            {
                strB.Append("Error - " + LastErrorStr);
            }
            else
            {
                strB.Append(String.Format(@" {0} = [ OK-{1} \ Bad-{2} ])"
                    , received, received, count - received));
            }
            strB.Append("");
            //txtLog.Invoke(new EventHandler(delegate
            //{
                //txtLog.Text = strB.ToString();
            //}));
        }
        [Flags]
        enum ConnectionState : int
        {
            INTERNET_CONNECTION_MODEM = 0x1,
            INTERNET_CONNECTION_LAN = 0x2,
            INTERNET_CONNECTION_PROXY = 0x4,
            INTERNET_RAS_INSTALLED = 0x10,
            INTERNET_CONNECTION_OFFLINE = 0x20,
            INTERNET_CONNECTION_CONFIGURED = 0x40
        }
        [DllImport("wininet", CharSet = CharSet.Auto)]
        static extern bool InternetGetConnectedState(ref ConnectionState lpdwFlags, int dwReserved);
        #endregion
    }
}
